//===----------------------------------------------------------------------===//
//
// This source file is part of the Soto for AWS open source project
//
// Copyright (c) 2017-2024 the Soto project authors
// Licensed under Apache License v2.0
//
// See LICENSE.txt for license information
// See CONTRIBUTORS.txt for the list of Soto project authors
//
// SPDX-License-Identifier: Apache-2.0
//
//===----------------------------------------------------------------------===//

// THIS FILE IS AUTOMATICALLY GENERATED by https://github.com/soto-project/soto-codegenerator.
// DO NOT EDIT.

#if canImport(FoundationEssentials)
import FoundationEssentials
#else
import Foundation
#endif
@_spi(SotoInternal) import SotoCore

extension BCMDashboards {
    // MARK: Enums

    public enum DashboardType: String, CustomStringConvertible, Codable, Sendable, CodingKeyRepresentable {
        case custom = "CUSTOM"
        public var description: String { return self.rawValue }
    }

    public enum DateTimeType: String, CustomStringConvertible, Codable, Sendable, CodingKeyRepresentable {
        case absolute = "ABSOLUTE"
        case relative = "RELATIVE"
        public var description: String { return self.rawValue }
    }

    public enum Dimension: String, CustomStringConvertible, Codable, Sendable, CodingKeyRepresentable {
        case az = "AZ"
        case billingEntity = "BILLING_ENTITY"
        case cacheEngine = "CACHE_ENGINE"
        case costCategoryName = "COST_CATEGORY_NAME"
        case databaseEngine = "DATABASE_ENGINE"
        case deploymentOption = "DEPLOYMENT_OPTION"
        case instanceType = "INSTANCE_TYPE"
        case instanceTypeFamily = "INSTANCE_TYPE_FAMILY"
        case legalEntityName = "LEGAL_ENTITY_NAME"
        case linkedAccount = "LINKED_ACCOUNT"
        case operatingSystem = "OPERATING_SYSTEM"
        case operation = "OPERATION"
        case platform = "PLATFORM"
        case purchaseType = "PURCHASE_TYPE"
        case recordType = "RECORD_TYPE"
        case region = "REGION"
        case reservationId = "RESERVATION_ID"
        case resourceId = "RESOURCE_ID"
        case savingsPlansType = "SAVINGS_PLANS_TYPE"
        case scope = "SCOPE"
        case service = "SERVICE"
        case subscriptionId = "SUBSCRIPTION_ID"
        case tagKey = "TAG_KEY"
        case tenancy = "TENANCY"
        case usageType = "USAGE_TYPE"
        case usageTypeGroup = "USAGE_TYPE_GROUP"
        public var description: String { return self.rawValue }
    }

    public enum Granularity: String, CustomStringConvertible, Codable, Sendable, CodingKeyRepresentable {
        case daily = "DAILY"
        case hourly = "HOURLY"
        case monthly = "MONTHLY"
        public var description: String { return self.rawValue }
    }

    public enum GroupDefinitionType: String, CustomStringConvertible, Codable, Sendable, CodingKeyRepresentable {
        case costCategory = "COST_CATEGORY"
        case dimension = "DIMENSION"
        case tag = "TAG"
        public var description: String { return self.rawValue }
    }

    public enum MatchOption: String, CustomStringConvertible, Codable, Sendable, CodingKeyRepresentable {
        case absent = "ABSENT"
        case caseInsensitive = "CASE_INSENSITIVE"
        case caseSensitive = "CASE_SENSITIVE"
        case contains = "CONTAINS"
        case endsWith = "ENDS_WITH"
        case equals = "EQUALS"
        case greaterThanOrEqual = "GREATER_THAN_OR_EQUAL"
        case startsWith = "STARTS_WITH"
        public var description: String { return self.rawValue }
    }

    public enum MetricName: String, CustomStringConvertible, Codable, Sendable, CodingKeyRepresentable {
        case amortizedCost = "AmortizedCost"
        case blendedCost = "BlendedCost"
        case cost = "Cost"
        case hour = "Hour"
        case netAmortizedCost = "NetAmortizedCost"
        case netUnblendedCost = "NetUnblendedCost"
        case normalizedUsageAmount = "NormalizedUsageAmount"
        case spendCoveredBySavingsPlans = "SpendCoveredBySavingsPlans"
        case unblendedCost = "UnblendedCost"
        case unit = "Unit"
        case usageQuantity = "UsageQuantity"
        public var description: String { return self.rawValue }
    }

    public enum VisualType: String, CustomStringConvertible, Codable, Sendable, CodingKeyRepresentable {
        case bar = "BAR"
        case line = "LINE"
        case stack = "STACK"
        public var description: String { return self.rawValue }
    }

    public enum DisplayConfig: AWSEncodableShape & AWSDecodableShape, Sendable {
        /// The configuration for graphical display of the widget data, including chart type and visual options.
        case graph([String: GraphDisplayConfig])
        /// The configuration for tabular display of the widget data.
        case table(TableDisplayConfigStruct)

        public init(from decoder: Decoder) throws {
            let container = try decoder.container(keyedBy: CodingKeys.self)
            guard container.allKeys.count == 1, let key = container.allKeys.first else {
                let context = DecodingError.Context(
                    codingPath: container.codingPath,
                    debugDescription: "Expected exactly one key, but got \(container.allKeys.count)"
                )
                throw DecodingError.dataCorrupted(context)
            }
            switch key {
            case .graph:
                let value = try container.decode([String: GraphDisplayConfig].self, forKey: .graph)
                self = .graph(value)
            case .table:
                let value = try container.decode(TableDisplayConfigStruct.self, forKey: .table)
                self = .table(value)
            }
        }

        public func encode(to encoder: Encoder) throws {
            var container = encoder.container(keyedBy: CodingKeys.self)
            switch self {
            case .graph(let value):
                try container.encode(value, forKey: .graph)
            case .table(let value):
                try container.encode(value, forKey: .table)
            }
        }

        public func validate(name: String) throws {
            switch self {
            case .graph(let value):
                try value.forEach {
                    try validate($0.key, name: "graph.key", parent: name, max: 1024)
                    try validate($0.key, name: "graph.key", parent: name, pattern: "^[\\S\\s]*$")
                }
            default:
                break
            }
        }

        private enum CodingKeys: String, CodingKey {
            case graph = "graph"
            case table = "table"
        }
    }

    public enum QueryParameters: AWSEncodableShape & AWSDecodableShape, Sendable {
        /// The parameters for querying cost and usage data, including metrics, time range, granularity, grouping dimensions, and filters.
        case costAndUsage(CostAndUsageQuery)
        /// The parameters for querying Reserved Instance coverage data, showing how much of your eligible instance usage is covered by Reserved Instances.
        case reservationCoverage(ReservationCoverageQuery)
        /// The parameters for querying Reserved Instance utilization data, showing how effectively your Reserved Instances are being used.
        case reservationUtilization(ReservationUtilizationQuery)
        /// The parameters for querying Savings Plans coverage data, showing how much of your eligible compute usage is covered by Savings Plans.
        case savingsPlansCoverage(SavingsPlansCoverageQuery)
        /// The parameters for querying Savings Plans utilization data, showing how effectively your Savings Plans are being used.
        case savingsPlansUtilization(SavingsPlansUtilizationQuery)

        public init(from decoder: Decoder) throws {
            let container = try decoder.container(keyedBy: CodingKeys.self)
            guard container.allKeys.count == 1, let key = container.allKeys.first else {
                let context = DecodingError.Context(
                    codingPath: container.codingPath,
                    debugDescription: "Expected exactly one key, but got \(container.allKeys.count)"
                )
                throw DecodingError.dataCorrupted(context)
            }
            switch key {
            case .costAndUsage:
                let value = try container.decode(CostAndUsageQuery.self, forKey: .costAndUsage)
                self = .costAndUsage(value)
            case .reservationCoverage:
                let value = try container.decode(ReservationCoverageQuery.self, forKey: .reservationCoverage)
                self = .reservationCoverage(value)
            case .reservationUtilization:
                let value = try container.decode(ReservationUtilizationQuery.self, forKey: .reservationUtilization)
                self = .reservationUtilization(value)
            case .savingsPlansCoverage:
                let value = try container.decode(SavingsPlansCoverageQuery.self, forKey: .savingsPlansCoverage)
                self = .savingsPlansCoverage(value)
            case .savingsPlansUtilization:
                let value = try container.decode(SavingsPlansUtilizationQuery.self, forKey: .savingsPlansUtilization)
                self = .savingsPlansUtilization(value)
            }
        }

        public func encode(to encoder: Encoder) throws {
            var container = encoder.container(keyedBy: CodingKeys.self)
            switch self {
            case .costAndUsage(let value):
                try container.encode(value, forKey: .costAndUsage)
            case .reservationCoverage(let value):
                try container.encode(value, forKey: .reservationCoverage)
            case .reservationUtilization(let value):
                try container.encode(value, forKey: .reservationUtilization)
            case .savingsPlansCoverage(let value):
                try container.encode(value, forKey: .savingsPlansCoverage)
            case .savingsPlansUtilization(let value):
                try container.encode(value, forKey: .savingsPlansUtilization)
            }
        }

        public func validate(name: String) throws {
            switch self {
            case .costAndUsage(let value):
                try value.validate(name: "\(name).costAndUsage")
            case .reservationCoverage(let value):
                try value.validate(name: "\(name).reservationCoverage")
            case .reservationUtilization(let value):
                try value.validate(name: "\(name).reservationUtilization")
            case .savingsPlansCoverage(let value):
                try value.validate(name: "\(name).savingsPlansCoverage")
            case .savingsPlansUtilization(let value):
                try value.validate(name: "\(name).savingsPlansUtilization")
            }
        }

        private enum CodingKeys: String, CodingKey {
            case costAndUsage = "costAndUsage"
            case reservationCoverage = "reservationCoverage"
            case reservationUtilization = "reservationUtilization"
            case savingsPlansCoverage = "savingsPlansCoverage"
            case savingsPlansUtilization = "savingsPlansUtilization"
        }
    }

    // MARK: Shapes

    public struct CostAndUsageQuery: AWSEncodableShape & AWSDecodableShape {
        /// The filter expression to be applied to the cost and usage data.
        public let filter: Expression?
        /// The granularity of the retrieved data: HOURLY, DAILY, or MONTHLY.
        public let granularity: Granularity
        /// Specifies how to group the retrieved data, such as by SERVICE, ACCOUNT, or TAG.
        public let groupBy: [GroupDefinition]?
        /// The specific cost and usage metrics to retrieve.  Valid values for CostAndUsageQuery metrics are AmortizedCost, BlendedCost, NetAmortizedCost, NetUnblendedCost, NormalizedUsageAmount, UnblendedCost, and UsageQuantity.
        public let metrics: [MetricName]
        /// The time period for which to retrieve data. Can be specified as absolute dates or relative time periods.
        public let timeRange: DateTimeRange

        @inlinable
        public init(filter: Expression? = nil, granularity: Granularity, groupBy: [GroupDefinition]? = nil, metrics: [MetricName], timeRange: DateTimeRange) {
            self.filter = filter
            self.granularity = granularity
            self.groupBy = groupBy
            self.metrics = metrics
            self.timeRange = timeRange
        }

        public func validate(name: String) throws {
            try self.timeRange.validate(name: "\(name).timeRange")
        }

        private enum CodingKeys: String, CodingKey {
            case filter = "filter"
            case granularity = "granularity"
            case groupBy = "groupBy"
            case metrics = "metrics"
            case timeRange = "timeRange"
        }
    }

    public struct CostCategoryValues: AWSEncodableShape & AWSDecodableShape {
        /// The key of the cost category to filter on.
        public let key: String?
        /// The match options for cost category values, such as EQUALS, CONTAINS, STARTS_WITH, or ENDS_WITH.
        public let matchOptions: [MatchOption]?
        /// The values to match for the specified cost category key.
        public let values: [String]?

        @inlinable
        public init(key: String? = nil, matchOptions: [MatchOption]? = nil, values: [String]? = nil) {
            self.key = key
            self.matchOptions = matchOptions
            self.values = values
        }

        private enum CodingKeys: String, CodingKey {
            case key = "key"
            case matchOptions = "matchOptions"
            case values = "values"
        }
    }

    public struct CreateDashboardRequest: AWSEncodableShape {
        /// A description of the dashboard's purpose or contents.
        public let description: String?
        /// The name of the dashboard. The name must be unique within your account.
        public let name: String
        /// The tags to apply to the dashboard resource for organization and management.
        public let resourceTags: [ResourceTag]?
        /// An array of widget configurations that define the visualizations to be displayed in the dashboard. Each dashboard can contain up to 20 widgets.
        public let widgets: [Widget]

        @inlinable
        public init(description: String? = nil, name: String, resourceTags: [ResourceTag]? = nil, widgets: [Widget]) {
            self.description = description
            self.name = name
            self.resourceTags = resourceTags
            self.widgets = widgets
        }

        public func validate(name: String) throws {
            try self.validate(self.description, name: "description", parent: name, max: 200)
            try self.validate(self.description, name: "description", parent: name, min: 1)
            try self.validate(self.description, name: "description", parent: name, pattern: "^(?!.* {2})[ a-zA-Z0-9.,!?;:@#$%&\\-_/\\\\]*$")
            try self.validate(self.name, name: "name", parent: name, max: 50)
            try self.validate(self.name, name: "name", parent: name, min: 2)
            try self.validate(self.name, name: "name", parent: name, pattern: "^(?!.* {2})[a-zA-Z][a-zA-Z0-9 _-]{0,48}[a-zA-Z0-9_-]$")
            try self.resourceTags?.forEach {
                try $0.validate(name: "\(name).resourceTags[]")
            }
            try self.validate(self.resourceTags, name: "resourceTags", parent: name, max: 200)
            try self.widgets.forEach {
                try $0.validate(name: "\(name).widgets[]")
            }
            try self.validate(self.widgets, name: "widgets", parent: name, max: 20)
        }

        private enum CodingKeys: String, CodingKey {
            case description = "description"
            case name = "name"
            case resourceTags = "resourceTags"
            case widgets = "widgets"
        }
    }

    public struct CreateDashboardResponse: AWSDecodableShape {
        /// The ARN of the newly created dashboard.
        public let arn: String

        @inlinable
        public init(arn: String) {
            self.arn = arn
        }

        private enum CodingKeys: String, CodingKey {
            case arn = "arn"
        }
    }

    public struct DashboardReference: AWSDecodableShape {
        /// The ARN of the referenced dashboard.
        public let arn: String
        /// The timestamp when the dashboard was created.
        public let createdAt: Date
        /// The description of the referenced dashboard.
        public let description: String?
        /// The name of the referenced dashboard.
        public let name: String
        /// The dashboard type.
        public let type: DashboardType
        /// The timestamp when the dashboard was last modified.
        public let updatedAt: Date

        @inlinable
        public init(arn: String, createdAt: Date, description: String? = nil, name: String, type: DashboardType, updatedAt: Date) {
            self.arn = arn
            self.createdAt = createdAt
            self.description = description
            self.name = name
            self.type = type
            self.updatedAt = updatedAt
        }

        private enum CodingKeys: String, CodingKey {
            case arn = "arn"
            case createdAt = "createdAt"
            case description = "description"
            case name = "name"
            case type = "type"
            case updatedAt = "updatedAt"
        }
    }

    public struct DateTimeRange: AWSEncodableShape & AWSDecodableShape {
        /// The end time of the date range for querying data.
        public let endTime: DateTimeValue
        /// The start time of the date range for querying data.
        public let startTime: DateTimeValue

        @inlinable
        public init(endTime: DateTimeValue, startTime: DateTimeValue) {
            self.endTime = endTime
            self.startTime = startTime
        }

        public func validate(name: String) throws {
            try self.endTime.validate(name: "\(name).endTime")
            try self.startTime.validate(name: "\(name).startTime")
        }

        private enum CodingKeys: String, CodingKey {
            case endTime = "endTime"
            case startTime = "startTime"
        }
    }

    public struct DateTimeValue: AWSEncodableShape & AWSDecodableShape {
        /// The type of date/time value: ABSOLUTE for specific dates or RELATIVE for dynamic time periods.
        public let type: DateTimeType
        /// The actual date/time value.
        public let value: String

        @inlinable
        public init(type: DateTimeType, value: String) {
            self.type = type
            self.value = value
        }

        public func validate(name: String) throws {
            try self.validate(self.value, name: "value", parent: name, max: 1024)
            try self.validate(self.value, name: "value", parent: name, pattern: "^[\\S\\s]*$")
        }

        private enum CodingKeys: String, CodingKey {
            case type = "type"
            case value = "value"
        }
    }

    public struct DeleteDashboardRequest: AWSEncodableShape {
        /// The ARN of the dashboard to be deleted.
        public let arn: String

        @inlinable
        public init(arn: String) {
            self.arn = arn
        }

        public func validate(name: String) throws {
            try self.validate(self.arn, name: "arn", parent: name, max: 2048)
            try self.validate(self.arn, name: "arn", parent: name, min: 20)
            try self.validate(self.arn, name: "arn", parent: name, pattern: "^arn:aws[-a-z0-9]*:bcm-dashboards::[0-9]{12}:dashboard/(\\*|[-a-z0-9]+)$")
        }

        private enum CodingKeys: String, CodingKey {
            case arn = "arn"
        }
    }

    public struct DeleteDashboardResponse: AWSDecodableShape {
        /// The ARN of the dashboard that was deleted.
        public let arn: String

        @inlinable
        public init(arn: String) {
            self.arn = arn
        }

        private enum CodingKeys: String, CodingKey {
            case arn = "arn"
        }
    }

    public struct DimensionValues: AWSEncodableShape & AWSDecodableShape {
        /// The key of the dimension to filter on (for example, SERVICE, USAGE_TYPE, or OPERATION).
        public let key: Dimension
        /// The match options for dimension values, such as EQUALS, CONTAINS, STARTS_WITH, or ENDS_WITH.
        public let matchOptions: [MatchOption]?
        /// The values to match for the specified dimension key.
        public let values: [String]

        @inlinable
        public init(key: Dimension, matchOptions: [MatchOption]? = nil, values: [String]) {
            self.key = key
            self.matchOptions = matchOptions
            self.values = values
        }

        private enum CodingKeys: String, CodingKey {
            case key = "key"
            case matchOptions = "matchOptions"
            case values = "values"
        }
    }

    public final class Expression: AWSEncodableShape & AWSDecodableShape {
        /// A list of expressions to combine with AND logic.
        public let and: [Expression]?
        /// The cost category values to include in the filter expression.
        public let costCategories: CostCategoryValues?
        /// The dimension values to include in the filter expression.
        public let dimensions: DimensionValues?
        /// An expression to negate with NOT logic.
        public let not: Expression?
        /// A list of expressions to combine with OR logic.
        public let or: [Expression]?
        /// The tag values to include in the filter expression.
        public let tags: TagValues?

        @inlinable
        public init(and: [Expression]? = nil, costCategories: CostCategoryValues? = nil, dimensions: DimensionValues? = nil, not: Expression? = nil, or: [Expression]? = nil, tags: TagValues? = nil) {
            self.and = and
            self.costCategories = costCategories
            self.dimensions = dimensions
            self.not = not
            self.or = or
            self.tags = tags
        }

        private enum CodingKeys: String, CodingKey {
            case and = "and"
            case costCategories = "costCategories"
            case dimensions = "dimensions"
            case not = "not"
            case or = "or"
            case tags = "tags"
        }
    }

    public struct GetDashboardRequest: AWSEncodableShape {
        /// The ARN of the dashboard to retrieve. This is required to uniquely identify the dashboard.
        public let arn: String

        @inlinable
        public init(arn: String) {
            self.arn = arn
        }

        public func validate(name: String) throws {
            try self.validate(self.arn, name: "arn", parent: name, max: 2048)
            try self.validate(self.arn, name: "arn", parent: name, min: 20)
            try self.validate(self.arn, name: "arn", parent: name, pattern: "^arn:aws[-a-z0-9]*:bcm-dashboards::[0-9]{12}:dashboard/(\\*|[-a-z0-9]+)$")
        }

        private enum CodingKeys: String, CodingKey {
            case arn = "arn"
        }
    }

    public struct GetDashboardResponse: AWSDecodableShape {
        /// The ARN of the retrieved dashboard.
        public let arn: String
        /// The timestamp when the dashboard was created.
        public let createdAt: Date
        /// The description of the retrieved dashboard.
        public let description: String?
        /// The name of the retrieved dashboard.
        public let name: String
        /// Indicates the dashboard type.
        public let type: DashboardType
        /// The timestamp when the dashboard was last modified.
        public let updatedAt: Date
        /// An array of widget configurations that make up the dashboard.
        public let widgets: [Widget]

        @inlinable
        public init(arn: String, createdAt: Date, description: String? = nil, name: String, type: DashboardType, updatedAt: Date, widgets: [Widget]) {
            self.arn = arn
            self.createdAt = createdAt
            self.description = description
            self.name = name
            self.type = type
            self.updatedAt = updatedAt
            self.widgets = widgets
        }

        private enum CodingKeys: String, CodingKey {
            case arn = "arn"
            case createdAt = "createdAt"
            case description = "description"
            case name = "name"
            case type = "type"
            case updatedAt = "updatedAt"
            case widgets = "widgets"
        }
    }

    public struct GetResourcePolicyRequest: AWSEncodableShape {
        /// The ARN of the dashboard whose resource-based policy you want to retrieve.
        public let resourceArn: String

        @inlinable
        public init(resourceArn: String) {
            self.resourceArn = resourceArn
        }

        public func validate(name: String) throws {
            try self.validate(self.resourceArn, name: "resourceArn", parent: name, max: 2048)
            try self.validate(self.resourceArn, name: "resourceArn", parent: name, min: 20)
            try self.validate(self.resourceArn, name: "resourceArn", parent: name, pattern: "^arn:aws[-a-z0-9]*:bcm-dashboards::[0-9]{12}:dashboard/(\\*|[-a-z0-9]+)$")
        }

        private enum CodingKeys: String, CodingKey {
            case resourceArn = "resourceArn"
        }
    }

    public struct GetResourcePolicyResponse: AWSDecodableShape {
        /// The JSON policy document that represents the dashboard's resource-based policy.
        public let policyDocument: String
        /// The ARN of the dashboard for which the resource-based policy was retrieved.
        public let resourceArn: String

        @inlinable
        public init(policyDocument: String, resourceArn: String) {
            self.policyDocument = policyDocument
            self.resourceArn = resourceArn
        }

        private enum CodingKeys: String, CodingKey {
            case policyDocument = "policyDocument"
            case resourceArn = "resourceArn"
        }
    }

    public struct GraphDisplayConfig: AWSEncodableShape & AWSDecodableShape {
        /// The type of visualization to use for the data.
        public let visualType: VisualType

        @inlinable
        public init(visualType: VisualType) {
            self.visualType = visualType
        }

        private enum CodingKeys: String, CodingKey {
            case visualType = "visualType"
        }
    }

    public struct GroupDefinition: AWSEncodableShape & AWSDecodableShape {
        /// The key to use for grouping cost and usage data.
        public let key: String
        /// The type of grouping to apply.
        public let type: GroupDefinitionType?

        @inlinable
        public init(key: String, type: GroupDefinitionType? = nil) {
            self.key = key
            self.type = type
        }

        private enum CodingKeys: String, CodingKey {
            case key = "key"
            case type = "type"
        }
    }

    public struct ListDashboardsRequest: AWSEncodableShape {
        /// The maximum number of results to return in a single call. The default value is 20.
        public let maxResults: Int?
        /// The token for the next page of results. Use the value returned in the previous response.
        public let nextToken: String?

        @inlinable
        public init(maxResults: Int? = nil, nextToken: String? = nil) {
            self.maxResults = maxResults
            self.nextToken = nextToken
        }

        public func validate(name: String) throws {
            try self.validate(self.maxResults, name: "maxResults", parent: name, max: 100)
            try self.validate(self.maxResults, name: "maxResults", parent: name, min: 1)
            try self.validate(self.nextToken, name: "nextToken", parent: name, max: 8192)
            try self.validate(self.nextToken, name: "nextToken", parent: name, min: 1)
            try self.validate(self.nextToken, name: "nextToken", parent: name, pattern: "^[\\S\\s]*$")
        }

        private enum CodingKeys: String, CodingKey {
            case maxResults = "maxResults"
            case nextToken = "nextToken"
        }
    }

    public struct ListDashboardsResponse: AWSDecodableShape {
        /// An array of dashboard references, containing basic information about each dashboard.
        public let dashboards: [DashboardReference]
        /// The token to use to retrieve the next page of results. Not returned if there are no more results to retrieve.
        public let nextToken: String?

        @inlinable
        public init(dashboards: [DashboardReference], nextToken: String? = nil) {
            self.dashboards = dashboards
            self.nextToken = nextToken
        }

        private enum CodingKeys: String, CodingKey {
            case dashboards = "dashboards"
            case nextToken = "nextToken"
        }
    }

    public struct ListTagsForResourceRequest: AWSEncodableShape {
        /// The unique identifier for the resource.
        public let resourceArn: String

        @inlinable
        public init(resourceArn: String) {
            self.resourceArn = resourceArn
        }

        public func validate(name: String) throws {
            try self.validate(self.resourceArn, name: "resourceArn", parent: name, max: 2048)
            try self.validate(self.resourceArn, name: "resourceArn", parent: name, min: 20)
            try self.validate(self.resourceArn, name: "resourceArn", parent: name, pattern: "^arn:aws[-a-z0-9]*:bcm-dashboards::[0-9]{12}:dashboard/(\\*|[-a-z0-9]+)$")
        }

        private enum CodingKeys: String, CodingKey {
            case resourceArn = "resourceArn"
        }
    }

    public struct ListTagsForResourceResponse: AWSDecodableShape {
        /// The list of tags associated with the specified dashboard resource.
        public let resourceTags: [ResourceTag]?

        @inlinable
        public init(resourceTags: [ResourceTag]? = nil) {
            self.resourceTags = resourceTags
        }

        private enum CodingKeys: String, CodingKey {
            case resourceTags = "resourceTags"
        }
    }

    public struct ReservationCoverageQuery: AWSEncodableShape & AWSDecodableShape {
        public let filter: Expression?
        /// The time granularity of the retrieved data: HOURLY, DAILY, or MONTHLY.
        public let granularity: Granularity?
        /// Specifies how to group the Reserved Instance coverage data, such as by service, Region, or instance type.
        public let groupBy: [GroupDefinition]?
        /// The coverage metrics to include in the results.  Valid values for ReservationCoverageQuery metrics are Hour, Unit, and Cost.
        public let metrics: [MetricName]?
        public let timeRange: DateTimeRange

        @inlinable
        public init(filter: Expression? = nil, granularity: Granularity? = nil, groupBy: [GroupDefinition]? = nil, metrics: [MetricName]? = nil, timeRange: DateTimeRange) {
            self.filter = filter
            self.granularity = granularity
            self.groupBy = groupBy
            self.metrics = metrics
            self.timeRange = timeRange
        }

        public func validate(name: String) throws {
            try self.timeRange.validate(name: "\(name).timeRange")
        }

        private enum CodingKeys: String, CodingKey {
            case filter = "filter"
            case granularity = "granularity"
            case groupBy = "groupBy"
            case metrics = "metrics"
            case timeRange = "timeRange"
        }
    }

    public struct ReservationUtilizationQuery: AWSEncodableShape & AWSDecodableShape {
        public let filter: Expression?
        /// The time granularity of the retrieved data: HOURLY, DAILY, or MONTHLY.
        public let granularity: Granularity?
        /// Specifies how to group the Reserved Instance utilization data, such as by service, Region, or instance type.
        public let groupBy: [GroupDefinition]?
        public let timeRange: DateTimeRange

        @inlinable
        public init(filter: Expression? = nil, granularity: Granularity? = nil, groupBy: [GroupDefinition]? = nil, timeRange: DateTimeRange) {
            self.filter = filter
            self.granularity = granularity
            self.groupBy = groupBy
            self.timeRange = timeRange
        }

        public func validate(name: String) throws {
            try self.timeRange.validate(name: "\(name).timeRange")
        }

        private enum CodingKeys: String, CodingKey {
            case filter = "filter"
            case granularity = "granularity"
            case groupBy = "groupBy"
            case timeRange = "timeRange"
        }
    }

    public struct ResourceTag: AWSEncodableShape & AWSDecodableShape {
        /// The key of the tag to be attached to the dashboard resource.
        public let key: String
        /// The value of the tag to be attached to the dashboard resource.
        public let value: String

        @inlinable
        public init(key: String, value: String) {
            self.key = key
            self.value = value
        }

        public func validate(name: String) throws {
            try self.validate(self.key, name: "key", parent: name, max: 128)
            try self.validate(self.key, name: "key", parent: name, min: 1)
            try self.validate(self.key, name: "key", parent: name, pattern: "^[\\S\\s]*$")
            try self.validate(self.value, name: "value", parent: name, max: 256)
            try self.validate(self.value, name: "value", parent: name, pattern: "^[\\S\\s]*$")
        }

        private enum CodingKeys: String, CodingKey {
            case key = "key"
            case value = "value"
        }
    }

    public struct SavingsPlansCoverageQuery: AWSEncodableShape & AWSDecodableShape {
        public let filter: Expression?
        /// The time granularity of the retrieved data: HOURLY, DAILY, or MONTHLY.
        public let granularity: Granularity?
        /// Specifies how to group the Savings Plans coverage data, such as by service or instance family.
        public let groupBy: [GroupDefinition]?
        /// The coverage metrics to include in the results.  Valid value for SavingsPlansCoverageQuery metrics is SpendCoveredBySavingsPlans.
        public let metrics: [MetricName]?
        public let timeRange: DateTimeRange

        @inlinable
        public init(filter: Expression? = nil, granularity: Granularity? = nil, groupBy: [GroupDefinition]? = nil, metrics: [MetricName]? = nil, timeRange: DateTimeRange) {
            self.filter = filter
            self.granularity = granularity
            self.groupBy = groupBy
            self.metrics = metrics
            self.timeRange = timeRange
        }

        public func validate(name: String) throws {
            try self.timeRange.validate(name: "\(name).timeRange")
        }

        private enum CodingKeys: String, CodingKey {
            case filter = "filter"
            case granularity = "granularity"
            case groupBy = "groupBy"
            case metrics = "metrics"
            case timeRange = "timeRange"
        }
    }

    public struct SavingsPlansUtilizationQuery: AWSEncodableShape & AWSDecodableShape {
        public let filter: Expression?
        /// The time granularity of the retrieved data: HOURLY, DAILY, or MONTHLY.
        public let granularity: Granularity?
        public let timeRange: DateTimeRange

        @inlinable
        public init(filter: Expression? = nil, granularity: Granularity? = nil, timeRange: DateTimeRange) {
            self.filter = filter
            self.granularity = granularity
            self.timeRange = timeRange
        }

        public func validate(name: String) throws {
            try self.timeRange.validate(name: "\(name).timeRange")
        }

        private enum CodingKeys: String, CodingKey {
            case filter = "filter"
            case granularity = "granularity"
            case timeRange = "timeRange"
        }
    }

    public struct TableDisplayConfigStruct: AWSEncodableShape & AWSDecodableShape {
        public init() {}
    }

    public struct TagResourceRequest: AWSEncodableShape {
        /// The unique identifier for the resource.
        public let resourceArn: String
        /// The tags to add to the dashboard resource.
        public let resourceTags: [ResourceTag]

        @inlinable
        public init(resourceArn: String, resourceTags: [ResourceTag]) {
            self.resourceArn = resourceArn
            self.resourceTags = resourceTags
        }

        public func validate(name: String) throws {
            try self.validate(self.resourceArn, name: "resourceArn", parent: name, max: 2048)
            try self.validate(self.resourceArn, name: "resourceArn", parent: name, min: 20)
            try self.validate(self.resourceArn, name: "resourceArn", parent: name, pattern: "^arn:aws[-a-z0-9]*:bcm-dashboards::[0-9]{12}:dashboard/(\\*|[-a-z0-9]+)$")
            try self.resourceTags.forEach {
                try $0.validate(name: "\(name).resourceTags[]")
            }
            try self.validate(self.resourceTags, name: "resourceTags", parent: name, max: 200)
        }

        private enum CodingKeys: String, CodingKey {
            case resourceArn = "resourceArn"
            case resourceTags = "resourceTags"
        }
    }

    public struct TagResourceResponse: AWSDecodableShape {
        public init() {}
    }

    public struct TagValues: AWSEncodableShape & AWSDecodableShape {
        /// The key of the tag to filter on.
        public let key: String?
        /// The match options for tag values, such as EQUALS, CONTAINS, STARTS_WITH, or ENDS_WITH.
        public let matchOptions: [MatchOption]?
        /// The values to match for the specified tag key.
        public let values: [String]?

        @inlinable
        public init(key: String? = nil, matchOptions: [MatchOption]? = nil, values: [String]? = nil) {
            self.key = key
            self.matchOptions = matchOptions
            self.values = values
        }

        private enum CodingKeys: String, CodingKey {
            case key = "key"
            case matchOptions = "matchOptions"
            case values = "values"
        }
    }

    public struct UntagResourceRequest: AWSEncodableShape {
        /// The unique identifier for the resource.
        public let resourceArn: String
        /// The keys of the tags to remove from the dashboard resource.
        public let resourceTagKeys: [String]

        @inlinable
        public init(resourceArn: String, resourceTagKeys: [String]) {
            self.resourceArn = resourceArn
            self.resourceTagKeys = resourceTagKeys
        }

        public func validate(name: String) throws {
            try self.validate(self.resourceArn, name: "resourceArn", parent: name, max: 2048)
            try self.validate(self.resourceArn, name: "resourceArn", parent: name, min: 20)
            try self.validate(self.resourceArn, name: "resourceArn", parent: name, pattern: "^arn:aws[-a-z0-9]*:bcm-dashboards::[0-9]{12}:dashboard/(\\*|[-a-z0-9]+)$")
            try self.resourceTagKeys.forEach {
                try validate($0, name: "resourceTagKeys[]", parent: name, max: 128)
                try validate($0, name: "resourceTagKeys[]", parent: name, min: 1)
                try validate($0, name: "resourceTagKeys[]", parent: name, pattern: "^[\\S\\s]*$")
            }
            try self.validate(self.resourceTagKeys, name: "resourceTagKeys", parent: name, max: 200)
        }

        private enum CodingKeys: String, CodingKey {
            case resourceArn = "resourceArn"
            case resourceTagKeys = "resourceTagKeys"
        }
    }

    public struct UntagResourceResponse: AWSDecodableShape {
        public init() {}
    }

    public struct UpdateDashboardRequest: AWSEncodableShape {
        /// The ARN of the dashboard to update.
        public let arn: String
        /// The new description for the dashboard. If not specified, the existing description is retained.
        public let description: String?
        /// The new name for the dashboard. If not specified, the existing name is retained.
        public let name: String?
        /// The updated array of widget configurations for the dashboard. Replaces all existing widgets.
        public let widgets: [Widget]?

        @inlinable
        public init(arn: String, description: String? = nil, name: String? = nil, widgets: [Widget]? = nil) {
            self.arn = arn
            self.description = description
            self.name = name
            self.widgets = widgets
        }

        public func validate(name: String) throws {
            try self.validate(self.arn, name: "arn", parent: name, max: 2048)
            try self.validate(self.arn, name: "arn", parent: name, min: 20)
            try self.validate(self.arn, name: "arn", parent: name, pattern: "^arn:aws[-a-z0-9]*:bcm-dashboards::[0-9]{12}:dashboard/(\\*|[-a-z0-9]+)$")
            try self.validate(self.description, name: "description", parent: name, max: 200)
            try self.validate(self.description, name: "description", parent: name, min: 1)
            try self.validate(self.description, name: "description", parent: name, pattern: "^(?!.* {2})[ a-zA-Z0-9.,!?;:@#$%&\\-_/\\\\]*$")
            try self.validate(self.name, name: "name", parent: name, max: 50)
            try self.validate(self.name, name: "name", parent: name, min: 2)
            try self.validate(self.name, name: "name", parent: name, pattern: "^(?!.* {2})[a-zA-Z][a-zA-Z0-9 _-]{0,48}[a-zA-Z0-9_-]$")
            try self.widgets?.forEach {
                try $0.validate(name: "\(name).widgets[]")
            }
            try self.validate(self.widgets, name: "widgets", parent: name, max: 20)
        }

        private enum CodingKeys: String, CodingKey {
            case arn = "arn"
            case description = "description"
            case name = "name"
            case widgets = "widgets"
        }
    }

    public struct UpdateDashboardResponse: AWSDecodableShape {
        /// The ARN of the updated dashboard.
        public let arn: String

        @inlinable
        public init(arn: String) {
            self.arn = arn
        }

        private enum CodingKeys: String, CodingKey {
            case arn = "arn"
        }
    }

    public struct Widget: AWSEncodableShape & AWSDecodableShape {
        /// An array of configurations that define the data queries and display settings for the widget.
        public let configs: [WidgetConfig]
        /// A description of the widget's purpose or the data it displays.
        public let description: String?
        /// The height of the widget in row spans. The dashboard layout consists of a grid system.
        public let height: Int?
        /// Specifies the starting column position of the widget in the dashboard's grid layout. Used to control widget placement.
        public let horizontalOffset: Int?
        /// The title of the widget.
        public let title: String
        /// The width of the widget in column spans. The dashboard layout consists of a grid system.
        public let width: Int?

        @inlinable
        public init(configs: [WidgetConfig], description: String? = nil, height: Int? = nil, horizontalOffset: Int? = nil, title: String, width: Int? = nil) {
            self.configs = configs
            self.description = description
            self.height = height
            self.horizontalOffset = horizontalOffset
            self.title = title
            self.width = width
        }

        public func validate(name: String) throws {
            try self.configs.forEach {
                try $0.validate(name: "\(name).configs[]")
            }
            try self.validate(self.configs, name: "configs", parent: name, max: 2)
            try self.validate(self.configs, name: "configs", parent: name, min: 1)
            try self.validate(self.description, name: "description", parent: name, max: 200)
            try self.validate(self.description, name: "description", parent: name, min: 1)
            try self.validate(self.description, name: "description", parent: name, pattern: "^(?!.* {2})[ a-zA-Z0-9.,!?;:@#$%&\\-_/\\\\]*$")
            try self.validate(self.height, name: "height", parent: name, max: 10)
            try self.validate(self.height, name: "height", parent: name, min: 4)
            try self.validate(self.title, name: "title", parent: name, max: 50)
            try self.validate(self.title, name: "title", parent: name, min: 2)
            try self.validate(self.title, name: "title", parent: name, pattern: "^(?!.* {2})[a-zA-Z0-9_-][ a-zA-Z0-9_-]*[a-zA-Z0-9_-]$")
            try self.validate(self.width, name: "width", parent: name, max: 6)
            try self.validate(self.width, name: "width", parent: name, min: 2)
        }

        private enum CodingKeys: String, CodingKey {
            case configs = "configs"
            case description = "description"
            case height = "height"
            case horizontalOffset = "horizontalOffset"
            case title = "title"
            case width = "width"
        }
    }

    public struct WidgetConfig: AWSEncodableShape & AWSDecodableShape {
        /// The configuration that determines how the retrieved data should be visualized in the widget.
        public let displayConfig: DisplayConfig
        /// The parameters that define what data the widget should retrieve and how it should be filtered or grouped.
        public let queryParameters: QueryParameters

        @inlinable
        public init(displayConfig: DisplayConfig, queryParameters: QueryParameters) {
            self.displayConfig = displayConfig
            self.queryParameters = queryParameters
        }

        public func validate(name: String) throws {
            try self.displayConfig.validate(name: "\(name).displayConfig")
            try self.queryParameters.validate(name: "\(name).queryParameters")
        }

        private enum CodingKeys: String, CodingKey {
            case displayConfig = "displayConfig"
            case queryParameters = "queryParameters"
        }
    }
}

// MARK: - Errors

/// Error enum for BCMDashboards
public struct BCMDashboardsErrorType: AWSErrorType {
    enum Code: String {
        case accessDeniedException = "AccessDeniedException"
        case internalServerException = "InternalServerException"
        case resourceNotFoundException = "ResourceNotFoundException"
        case serviceQuotaExceededException = "ServiceQuotaExceededException"
        case throttlingException = "ThrottlingException"
        case validationException = "ValidationException"
    }

    private let error: Code
    public let context: AWSErrorContext?

    /// initialize BCMDashboards
    public init?(errorCode: String, context: AWSErrorContext) {
        guard let error = Code(rawValue: errorCode) else { return nil }
        self.error = error
        self.context = context
    }

    internal init(_ error: Code) {
        self.error = error
        self.context = nil
    }

    /// return error code string
    public var errorCode: String { self.error.rawValue }

    /// You do not have sufficient permissions to perform this action. Verify your IAM permissions and any resource policies.
    public static var accessDeniedException: Self { .init(.accessDeniedException) }
    /// An internal error occurred while processing the request. Retry your request. If the problem persists, contact Amazon Web Services Support.
    public static var internalServerException: Self { .init(.internalServerException) }
    /// The specified resource (dashboard, policy, or widget) was not found. Verify the ARN and try again.
    public static var resourceNotFoundException: Self { .init(.resourceNotFoundException) }
    /// The request would exceed service quotas. For example, attempting to create more than 20 widgets in a dashboard or exceeding the maximum number of dashboards per account.
    public static var serviceQuotaExceededException: Self { .init(.serviceQuotaExceededException) }
    /// The request was denied due to request throttling. Reduce the frequency of requests and use exponential backoff.
    public static var throttlingException: Self { .init(.throttlingException) }
    /// The input parameters do not satisfy the requirements. Check the error message for specific validation details.
    public static var validationException: Self { .init(.validationException) }
}

extension BCMDashboardsErrorType: Equatable {
    public static func == (lhs: BCMDashboardsErrorType, rhs: BCMDashboardsErrorType) -> Bool {
        lhs.error == rhs.error
    }
}

extension BCMDashboardsErrorType: CustomStringConvertible {
    public var description: String {
        return "\(self.error.rawValue): \(self.message ?? "")"
    }
}
